package com.qfedu.edu.orderservice.service.impl;

import com.alibaba.fastjson.JSON;
import com.qfedu.edu.bo.CreateOrderBack;
import com.qfedu.edu.bo.OrderShow;
import com.qfedu.edu.bo.QueueMessage;
import com.qfedu.edu.constance.RabbitMQConstance;
import com.qfedu.edu.constance.RedisConstance;
import com.qfedu.edu.exception.BusinessException;
import com.qfedu.edu.manager.RabbitMQManager;
import com.qfedu.edu.manager.RedisManager;
import com.qfedu.edu.orderservice.service.OrderService;
import com.qfedu.edu.orderservice.utils.OrderNumberUtils;
import com.qfedu.edu.po.Class;
import com.qfedu.edu.po.Order;
import com.qfedu.edu.result.ResponseCode;
import com.qfedu.edu.vo.CreateOrderVo;
import lombok.extern.slf4j.Slf4j;
import org.qfedu.edu.service.IJwtService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.util.concurrent.TimeUnit;

/**
 * @author xiaobobo
 * @title: OrderServiceImpl
 * @projectName seckill-fy-2401-parent
 * @description: TODO
 * @date 2024/11/11  11:52
 */
@Service
@Slf4j
public class OrderServiceImpl implements OrderService {

    @Autowired
    private IJwtService jwtService;

    @Autowired
    private RedisManager redisManager;

    @Autowired
    private RabbitMQManager rabbitMQManager;

    @Override
    public CreateOrderBack createOrder(CreateOrderVo createOrderVo, HttpServletRequest req) throws UnsupportedEncodingException {
        //执行到这里 ：首先判断数据传输是否有误
        checkParam(createOrderVo);
        //封装Order对象
        OrderShow orderShow=getOrder(createOrderVo, req);
        //首先在Redis中实现减库存
        //记住 减库存并不是将库存-1
        //记录减库存的数量就可以了  key：stock:reduce:课程id  value：就是减库存的数量
        reduceStock(createOrderVo);
        //接下来就是将订单信息放到Redis中
        addOrderToRedis(orderShow,req);
        //还要将订单信息放到MQ中去 实现慢慢的下订单
        addOrderToMQ(orderShow);
        //封装返回对象
        String userId = jwtService.getUserId(req.getHeader("token"));
        CreateOrderBack createOrderBack = new CreateOrderBack();
        createOrderBack.setOrderNumber(orderShow.getOrderNum());
        createOrderBack.setUserId(userId);
        return createOrderBack;
    }

    @Override
    public OrderShow listOrderByOrderNumber(String orderNumber) {
        if(StringUtils.isEmpty(orderNumber)){
            throw new BusinessException(ResponseCode.PARAM_EXCEPTION);
        }
        //执行到这里 参数无误
        String orderJsonStr = redisManager.getString(orderNumber);
        //转换成对象
        OrderShow orderShow = JSON.parseObject(orderJsonStr, OrderShow.class);
        return orderShow;
    }

    /**
     * 将订单信息放到MQ中去
     * @param order
     */
    private void addOrderToMQ(Order order) throws UnsupportedEncodingException {
        QueueMessage queueMessage = new QueueMessage();
        //下订单
        queueMessage.setType(1);
        queueMessage.setQueueName(RabbitMQConstance.getOrderName());
        queueMessage.setMessage(JSON.toJSONString(order));
        //将这个对象发送到MQ中去
        rabbitMQManager.sendWork(RabbitMQConstance.getOrderName(),JSON.toJSONString(queueMessage));
        //TODO 还要向TTL队列发送消息
        QueueMessage queueMessage1 = new QueueMessage();
        //表示的是订单状态检测的这个队列
        queueMessage1.setType(5);
        queueMessage1.setQueueName(RabbitMQConstance.getOrderTtlName());
        queueMessage1.setMessage(JSON.toJSONString(order));
        rabbitMQManager.sendWork(RabbitMQConstance.getOrderTtlName(),JSON.toJSONString(queueMessage1));
    }

    /**
     * 将订单信息添加到Redis中去
     * @param order
     * @param req
     */
    private void addOrderToRedis(OrderShow order, HttpServletRequest req) {
        //第二步：找到用户id
        String userId = getUserId(req);
        //设计key order:用户id  订单信息的JSON格式...
        //String orderKey=RedisConstance.getOrderPrefix()+userId;
        //接下来就可以向订单表中添加数据了...
        redisManager.addString(order.getOrderNum(), JSON.toJSONString(order),60, TimeUnit.DAYS);
        log.info("订单信息成功添加到Redis中");
    }

    /**
     * 减库存的实现
     * @param createOrderVo
     */
    private void reduceStock(CreateOrderVo createOrderVo) {
        //拿到这个课程id
        String classId = createOrderVo.getClassId();
        //接下来构建这样的一个key
        String reduceStockKey= RedisConstance.getStockReducePrefix()+classId;
        //接下来就可以计数了
        redisManager.incr(reduceStockKey,1);
        log.info("在Redis中实现减库存成功....");
    }

    /**
     * 获取订单对象
     * @param createOrderVo
     * @param req
     */
    private OrderShow getOrder(CreateOrderVo createOrderVo, HttpServletRequest req) {
        //第二步：找到用户id
        String userId = getUserId(req);
        //第三步：生成订单号....
        String orderNumber = OrderNumberUtils.createOrderNumber(createOrderVo.getClassId());
        //第四步：向订单表中插入数据 ?  这里注意：前端有高并发的情况 那么这里如果直接向数据库添加数据的话 那么MySQL会死  所以这里不能直接向数据库添加数据?
        OrderShow order = new OrderShow();
        order.setOrderNum(orderNumber);
        order.setActualFee(createOrderVo.getSecKillPrice().longValue());
        order.setUserId(userId);
        order.setTotalFee(createOrderVo.getSecKillPrice().longValue());
        order.setInvoiceType(0);
        order.setStatus(0);
        order.setPrice(createOrderVo.getPrice());
        order.setClassId(createOrderVo.getClassId());
        order.setClassName(createOrderVo.getClassName());
        //这里需要去Redis中查询这个数据的图片
        String key=RedisConstance.getProInfoPrefix()+createOrderVo.getClassId();
        String saveMessage = redisManager.getString(key);
        //将这个信息转换成Class对象
        Class aClass = JSON.parseObject(saveMessage, Class.class);
        order.setPhoto(aClass.getPhoto());
        return order;
    }

    /**
     * 找到用户id
     *
     * @param req
     * @return
     */
    private String getUserId(HttpServletRequest req) {
        String token = req.getHeader("token");
        return jwtService.getUserId(token);
    }

    /**
     * 校验参数的合法性
     *
     * @param createOrderVo
     */
    private void checkParam(CreateOrderVo createOrderVo) {
        if (null == createOrderVo || null == createOrderVo.getPrice() || null == createOrderVo.getSecKillPrice() || null == createOrderVo.getQuantity() || StringUtils.isEmpty(createOrderVo.getClassName()) || StringUtils.isEmpty(createOrderVo.getClassId())) {
            throw new BusinessException(ResponseCode.PARAM_EXCEPTION);
        }
    }
}
